﻿using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace Nomo.UnityCoreModule.Enumerators
{
    /// <summary>
    /// 等待，直到传入的方法序列的任何一个成员的返回值为 <see langword="true"/> .
    /// </summary>
    public sealed class WaitAny : CustomYieldInstruction
    {
        private readonly Func<bool>[] _predicates;

        /// <inheritdoc />
        public override bool keepWaiting
        {
            get
            {
                for (var i = 0; i < _predicates.Length; i++)
                {
                    if (_predicates[i]())
                    {
                        Index = i;
                        return false;
                    }
                }

                return true;
            }
        }

        /// <summary>
        /// 返回在传入的方法序列中第一个返回值为 <see langword="true"/> 的方法的索引值。如果协程还没有运行结束，则会返回 -1 .
        /// </summary>
        public int Index { get; private set; }

        /// <summary>
        /// 使用指定的方法序列初始化 <see cref="WaitAny"/> 类的新实例。
        /// </summary>
        /// <param name="predicates">方法序列，它的每个成员都是返回值为 <see cref="bool"/> 、没有参数的方法。</param>
        /// <exception cref="ArgumentNullException"><paramref name="predicates"/> 为 <see langword="null"/> .</exception>
        /// <exception cref="ArgumentException"><paramref name="predicates"/> 中没有成员，或含有值为 <see langword="null"/> 的成员。</exception>
        public WaitAny(IEnumerable<Func<bool>> predicates)
        {
            if (predicates == null)
            {
                throw new ArgumentNullException(nameof(predicates));
            }
            var predicatesArray = predicates as Func<bool>[] ?? predicates.ToArray();
            if (predicatesArray.Length == 0)
            {
                throw new ArgumentException($"{nameof(predicates)} 中没有成员。");
            }
            if (predicatesArray.Any(e => e == null))
            {
                throw new ArgumentException($"{nameof(predicates)} 含有值为 {null} 的成员。", nameof(predicates));
            }

            _predicates = predicatesArray;
            Index       = -1;
        }
    }
}
